#include "Server.h"


Server::Server(int p, ByteQueue *q){
	this->port = p;
	queue = q;
	numOfCon = 0;
}

Server::~Server(void){
	if(this->isRunning){
		this->isRunning = FALSE;
		WaitForSingleObject(this->hThread, INFINITE);
		for(int i=0;i<numOfCon;i++)
			closesocket(connections[i].socket);
		closesocket(this->serverSocket);
		WSACleanup();
	}
}

void Server::setNotifyTo(HWND hwnd){
	this->notifyTo = hwnd;
}

int Server::broadcase(BYTE *data, int len){
	int i, c = 0;
	for(i=0;i<numOfCon;i++)
		if(connections[i].sendData(data, len) != SOCKET_ERROR)
			c++;

	return c;
}

BOOL Server::start(){
	int error = WSAStartup(0x0202, &wsa);
	if(error)
		return FALSE;

	if(wsa.wVersion != 0x0202){
		WSACleanup();
		return FALSE;
	}

	this->serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(serverSocket==INVALID_SOCKET)
	{
		MessageBox(notifyTo,L"Socket creation failed",L"Critical Error",MB_ICONERROR);
		//SendMessage(hWnd,WM_DESTROY,NULL,NULL);
		WSACleanup();
		return FALSE;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	//addr.sin_addr.s_addr = inet_addr("171.242.43.26");

	if(bind(serverSocket,(LPSOCKADDR)&addr,sizeof(addr))==SOCKET_ERROR)
	{
		MessageBox(notifyTo,L"Unable to bind socket",L"Error",MB_OK);
		//SendMessage(hWnd,WM_DESTROY,NULL,NULL);
		WSACleanup();
		return FALSE;
	}

	/*
    if(!WSAAsyncSelect (serverSocket, hwnd, 1045, FD_READ | FD_CONNECT | FD_CLOSE)){
		WSACleanup();
		return FALSE;
	}
	*/
	
	if(listen(serverSocket, 10) == SOCKET_ERROR){
		error = WSAGetLastError(); 
		switch(error){
			case WSANOTINITIALISED:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAENETDOWN:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAEADDRINUSE:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAEINPROGRESS:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAEINVAL:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAEISCONN:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAEMFILE:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAENOBUFS:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;

			case WSAENOTSOCK:
				MessageBox(notifyTo, L"WSAENOTSOCK", L"Error", MB_OK);
				break;

			case WSAEOPNOTSUPP:
				MessageBox(notifyTo, L"Khong the tao duoc custom ctrl", L"Error", MB_OK);
				break;
		}
		WSACleanup();
		return FALSE;
	}

	hQueueThread = CreateThread(NULL, 0, Server::queue_handling, (LPVOID)this, 0, &(this->dwQueueThreadId));

	hThread = CreateThread(NULL, 0, Server::server_run, (LPVOID)this, 0, &(this->dwThreadId));

	return TRUE;
}

DWORD WINAPI Server::server_run(VOID *p){
	Server *_this = (Server*)p;
	int len = sizeof(_this->addr);
	int i = 0;

	while(_this->isRunning){
		if(_this->numOfCon < MAXCLIENT){
			_this->connections[_this->numOfCon].socket = accept(_this->serverSocket, (struct sockaddr*)&(_this->addr), &len);
			_this->connections[_this->numOfCon].queue = _this->queue;
			_this->connections[_this->numOfCon].isRunning = TRUE;
			_this->connections[_this->numOfCon].setNotifyTo(_this->notifyTo);
			_this->connections[_this->numOfCon].hThread = CreateThread(NULL, 0, Connection::connection_service, (LPVOID)&(_this->connections[i]), 0, &(_this->connections[i].dwThreadId));
			_this->numOfCon++;
			MessageBox(_this->notifyTo, L"Accepted a connection", L"Incomming connection", MB_OK);
		}
	}

	return 0;
}

DWORD WINAPI Server::queue_handling(VOID *p){
	Server *_this = (Server*)p;
	BYTE buf[1024];
	int l = 0;
	while(_this->isRunning){
		//WaitForSingleObject( _this->queue->hEvent_not_empty, INFINITE );
		if(! (_this->queue->isEmpty()) ){
			_this->queue->remove(buf, l);
			//SetEvent( _this->queue->hEvent );
			//ResetEvent(_this->queue->hEvent);
			//MessageBox(_this->notifyTo,L"Receive data",L"Incoming connection",MB_ICONINFORMATION);
		}
	}
	return 0;
}
